home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-01-15 | 66.9 KB | 2,154 lines | [TEXT/MPS ] |
- /*
- File: DLPIRoutines.c
-
- Contains: This file contains the routine(s) to handle the DLPI calls from the
- client. This file is very hardware independent.
-
- Written by:
-
- Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <FW2> 8/1/96 ES Took out unused local variables.
- <1> 3/27/96 ES first checked in
-
- To Do:
- */
-
- //-----------------------------------------------------------------------------------------
- // Include files
- //-----------------------------------------------------------------------------------------
-
- #include <OpenTptModule.h> // Open Transport files
- #include <OpenTptDevLinks.h>
- #include <OpenTptLinks.h>
- #include <stropts.h>
- #include <dlpi.h>
-
- #include <OSUtils.h> // System files
- #include <Kernel.h>
- #include <DriverServices.h>
- #include <NameRegistry.h>
- #include <Interrupts.h>
-
-
- #include "EntryPoints.h" // our files
- #include "DLPIRoutines.h"
- #include "HWSpecific.h"
- /*zzz*/
- static char debugStr[256];
- /*zzz*/
-
- //-----------------------------------------------------------------------------------------
- // Global variable for the entire CFM
- //-----------------------------------------------------------------------------------------
-
- extern DLPIPrivateData *gDLPIPrivateData; // Declared in EntryPoints.c
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // A message block is passed to this routine, the routine determines if the message
- // block can handled a certain size of data. The reuse algorithm is done in this
- // order:
- //
- // 1. Reuse M_(PC)PROTO if available.
- // 2. Try to prepend header to first data block.
- // 3. Allocate a new message block to hold the header.
- //
- // Input:
- // mp - attempt to reuse the message block for a new message
- // dataSizeNeeded - indicates the size of the new message needed
- //
- // Output:
- // message block pointer - to a newly allocate message block or the original mb
- //
- //-----------------------------------------------------------------------------------------
- mblk_t *ReuseMessageBlock(mblk_t *mp,UInt16 dataSizeNeeded)
- {
- mblk_t *nmp;
-
- if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim - mp->b_datap->db_base) >= dataSizeNeeded))
- {
- mp->b_datap->db_type = M_DATA;
- mp->b_rptr = mp->b_datap->db_base;
- mp->b_wptr = mp->b_datap->db_base + dataSizeNeeded;
- }
- else
- {
- nmp = mp->b_cont; // grab the M_DATA blocks
- mp->b_cont = NULL; // detach the M_(PC)PROTO
- freemsg(mp); // free the M_(PC)PROTO
- mp = nmp; // point to the M_DATA blocks
-
- // try to get space on the first M_DATA block
- if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= dataSizeNeeded))
- mp->b_rptr -= dataSizeNeeded;
- else
- {
- if ((nmp = allocb(dataSizeNeeded, BPRI_HI)) == NULL) // try to allocate a new message
- { // could not get a new message block so lets forget about the message altogether
- freemsg(mp); // free the original M_DATA portion of the message
- mp = NULL; // indicates the reuse failed
- }
- else
- {
- nmp->b_cont = mp; // attach the new message block as the head
- nmp->b_wptr += dataSizeNeeded;
- mp = nmp;
- }
- }
- }
-
- return mp;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds a header for a packet that will be transmitted. The passed
- // in message (mp) has the header info in the first message block and then
- // data in the following message blocks. This routine uses the destination address
- // info in the first message block to construct an Ethernet header which includes
- // the dest, source (0, till sending packet), protocol/length (depends on the type
- // of packet), and possible 802.2 sap and snap. This header
- // will contain the source, destination, type/length, and SAP/SNAP components. The
- // header that is built can be used for a packet header or a fast path header.
- //
- // Input:
- // theStream - the stream originating the packet
- // mp - message block that contains info (source)
- // forFastPathOnly - this flag determines if this is for the Mentat fastpath or
- // a real packet header
- //
- // Output:
- // returns a message block that contains a formed packet header
- //
- //-----------------------------------------------------------------------------------------
- mblk_t *BuildTxPacketHeader(DLPIStream *theStream, mblk_t *mp, Boolean forFastPathOnly)
- {
-
- UInt16 hdrsize, datasize, dlsap;
- struct T8022FullPacketHeader *packetHeader;
- UInt8 *snapStart;
- UInt16 proto,packetType;
- UInt8 ctrl, responseFlag = 0;
- UInt8 destAddrCopy[kMaxBoundAddrLength], *destAddrOrig, *reqStart;
- UInt32 destAddrLen;
-
- reqStart = mp->b_rptr;
-
- switch (((union DL_primitives *)(reqStart))->dl_primitive)
- {
- case DL_UNITDATA_REQ:
- destAddrOrig = ((UInt8*)reqStart) + ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_offset;
- destAddrLen = ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_length;
- ctrl = 0x03;
- break;
-
- case DL_TEST_REQ:
- destAddrOrig = ((UInt8*)reqStart) + ((dl_test_req_t*)reqStart)->dl_dest_addr_offset;
- destAddrLen = ((dl_test_req_t*)reqStart)->dl_dest_addr_length;
- ctrl = (((dl_test_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
- break;
-
- case DL_XID_REQ:
- destAddrOrig = ((UInt8*)reqStart) + ((dl_xid_req_t*)reqStart)->dl_dest_addr_offset;
- destAddrLen = ((dl_xid_req_t*)reqStart)->dl_dest_addr_length;
- ctrl = (((dl_xid_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
- break;
-
- case DL_TEST_RES:
- destAddrOrig = ((UInt8*)reqStart) + ((dl_test_res_t*)reqStart)->dl_dest_addr_offset;
- destAddrLen = ((dl_test_res_t*)reqStart)->dl_dest_addr_length;
- ctrl = (((dl_test_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
- responseFlag = 1;
- break;
-
- case DL_XID_RES:
- destAddrOrig = ((UInt8*)reqStart) + ((dl_xid_res_t*)reqStart)->dl_dest_addr_offset;
- destAddrLen = ((dl_xid_res_t*)reqStart)->dl_dest_addr_length;
- ctrl = (((dl_xid_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
- responseFlag = 1;
- break;
- default:
- freemsg(mp);
- return NULL;
- break;
- }
-
- switch(destAddrLen)
- {
- case kEnetPhysicalAddressLength:
- dlsap = theStream->dlsap;
- break;
- case kEnetAndSAPAddressLength:
- dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
- break;
- case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // snap sap
- dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
- break;
- default:
- dlsap = theStream->dlsap;
- break;
- }
-
- datasize = msgdsize(mp); // this does not include header info
-
- packetType = ClassifyPacketType(theStream->dlsap,dlsap);
-
- switch(packetType)
- {
- case kPktDIX:
- hdrsize = kEnetPacketHeaderLength;
- proto = dlsap;
- break;
- case kPkt8022SAP:
- hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength;
- if (forFastPathOnly)
- proto = 0;
- else
- proto = (datasize + k8022BasicHeaderLength);
- break;
- case kPkt8022SNAP:
- hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
- if (forFastPathOnly)
- proto = 0;
- else
- proto = datasize + k8022SNAPHeaderLength;
- break;
- case kPktIPX:
- hdrsize = kEnetPacketHeaderLength;
- if (forFastPathOnly)
- proto = 0;
- else
- proto = datasize;
- break;
- default:
- hdrsize = kEnetPacketHeaderLength;
- proto = dlsap;
- break;
- }
-
- // we need to copy the dest address info in the message before we can reuse it
- bcopy(destAddrOrig, destAddrCopy, destAddrLen);
-
- if ((mp = ReuseMessageBlock(mp,hdrsize)) == NULL)
- return NULL;
-
- packetHeader = (struct T8022FullPacketHeader *)mp->b_rptr;
-
- packetHeader->fEnetPart.fProto = proto; // set proto or length
-
- switch(packetType)
- {
- case kPkt8022SAP:
- packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
- packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
- packetHeader->f8022Part.fCtrl = ctrl;
- break;
- case kPkt8022SNAP:
- packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
- packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
- packetHeader->f8022Part.fCtrl = ctrl;
- if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength)
- snapStart = destAddrCopy + kEnetAndSAPAddressLength;
- else
- snapStart = theStream->snap;
- OTCopy8022SNAP(snapStart,packetHeader->f8022Part.fSNAP);
- break;
- default:
- break;
- }
-
- OTCopy48BitAddress(destAddrCopy,packetHeader->fEnetPart.fDestAddr);
-
- return(mp);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks if the address is a multicast address, broadcast, or standard
- // address.
- //
- // Input:
- // addr - pointer to an array of 6 bytes that is an ethernet address
- //
- // Output:
- // return type of address
- //
- //-----------------------------------------------------------------------------------------
- SInt32 GetAddressType(UInt8 *addr)
- {
-
- if (addr[0] & 1) // is address multicast or broadcast
- {
- if (OTIs48BitBroadcastAddress(addr))
- return keaBroadcast;
- else
- return keaMulticast;
- }
- else
- return keaStandardAddress;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles the binding of a stream. The stream must not be in the
- // bind state when this call is made. In other words, a stream can only be bound
- // once. The call is ack'd by doing sending a message block with a bind ack
- // message.
- //
- // Input:
- // theStream - the stream that the client wants to bind
- // mp - message block that contains the parameters for the bind call
- //
- // Output:
- // returns the status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 BindTheStream(DLPIStream *theStream, mblk_t *mp)
- {
- dl_bind_req_t *req = (dl_bind_req_t *)mp->b_rptr;
- UInt16 dlsap = (UInt16)req->dl_sap;
- mblk_t *ack_mp;
- SInt32 i;
-
- if (req->dl_service_mode != DL_CLDLS)
- return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0));
-
- if (theStream->dlpiState != DL_UNBOUND)
- return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_OUTSTATE, 0));
-
- // don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF)
- // because it looks like IPX
- if ((dlsap < kMax8022SAP) && (dlsap & 1))
- return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
-
- if (ClassifyPacketType(dlsap,dlsap) == kPktUnknown)
- return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
-
- if ((ack_mp = BuildBindAck(theStream, dlsap)) == NULL)
- return (kdlpiRETRY);
-
- for (i = 0; i < kGroupSAPMapSize; i++)
- theStream->group_sap[i] = 0;
-
- if (dlsap <= kMax8022SAP)
- SetGroupSAP(theStream, k8022GlobalSAP);
-
- if (req->dl_xidtest_flg & DL_AUTO_XID)
- theStream->streamFlags |= kAutoXID;
-
- if (req->dl_xidtest_flg & DL_AUTO_TEST)
- theStream->streamFlags |= kAutoTest;
-
- freemsg(mp);
-
- theStream->dlpiState = DL_IDLE;
- theStream->dlsap = dlsap;
- theStream->streamFlags &= ~kSnapStream;
- putnext(theStream->readQueue, ack_mp); // and reply with the ACK
- return (kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds the bind ack message block.
- //
- // Input:
- // theStream - the stream to send the bind ack to
- // dlsap - the sap for the current stream
- //
- // Output:
- // returns a message block that contains the bind ack message
- //
- //-----------------------------------------------------------------------------------------
- mblk_t *BuildBindAck(DLPIStream *theStream, UInt16 dlsap)
- {
- dl_bind_ack_t *ackp;
- mblk_t *mp;
- T8022AddressStruct *addrInfo;
-
- if ((mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength);
- return(NULL);
- }
-
- mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_bind_ack_t *)mp->b_rptr;
- ackp->dl_primitive = DL_BIND_ACK;
- ackp->dl_sap = dlsap;
- ackp->dl_addr_length = kEnetAndSAPAddressLength;
- ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
- ackp->dl_max_conind = 0;
- ackp->dl_xidtest_flg = 0;
-
- addrInfo = (T8022AddressStruct *)(mp->b_rptr + sizeof(dl_bind_ack_t));
- OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,addrInfo->fHWAddr);
- addrInfo->fSAP = dlsap;
-
- // must move b_wptr past the address info data
- mp->b_wptr = mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength;
-
- return(mp);
- }
-
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds a header from a packet that was received. The header
- // includes the destination and source address. The sap and snap are also
- // copied.
- //
- // Ethernet Header
- // +-----------------------+
- // packetHeader | dest addr | 6 bytes
- // +-----------------------+
- // | src addr | 6 bytes
- // +-----------------------+
- // | type/protocol | 2 bytes
- // +-----------------------+
- // | dest SAP | 1 bytes 802.2 and IPX only
- // +-----------------------+
- // | src SAP | 1 bytes 802.2 and IPX only
- // +-----------------------+
- // | control | 1 bytes 802.2 only
- // +-----------------------+
- // | SNAP | 5 bytes 802.2 and 0xAA dest sap
- // +-----------------------+
- //
- // The Ethernet header information must be moved into a memory block with
- // the following format:
- //
- // Indication Header
- // +-----------------------+
- // destAddr | dest addr | 6 - 13 bytes
- // +-----------------------+
- // srcAddr | src addr | 6 - 13 bytes
- // +-----------------------+
- //
- // The Indication header destination and source address fields can contain from
- // 6 to 13 bytes. The minimum is the Ethernet addresses from the Ethernet header.
- // They could also contain the sap and snap information:
- //
- // dest or src addr format
- // +-----------------------+
- // | Ethernet addr | 6 bytes
- // +-----------------------+
- // | SAP | 2 bytes
- // +-----------------------+
- // | SNAP | 5 bytes
- // +-----------------------+
- //
- // Input:
- // mp - message block that contains the info for building a test message
- // dlsap_length - the number of bytes in the mp message block
- //
- // Output:
- // returns a message block that contains an the test message
- //
- //-----------------------------------------------------------------------------------------
- void BuildRxDestSrcHeader(T8022FullPacketHeader *packetHeader,
- T8022AddressStruct *destAddr,
- T8022AddressStruct *srcAddr,
- UInt32 dlsap_length)
-
- {
-
- OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr,destAddr->fHWAddr);
- OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr,srcAddr->fHWAddr);
-
- // Pull 8022 SAP from packet, if bytes remain in the dlsap_length.
-
- switch (dlsap_length)
- {
- case kEnetAndSAPAddressLength + k8022SNAPLength:
- OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,destAddr->fSNAP);
- OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,srcAddr->fSNAP);
- // no break because we want to do the sap also
- case kEnetAndSAPAddressLength:
- destAddr->fSAP = packetHeader->f8022Part.fDSAP;
- srcAddr->fSAP = packetHeader->f8022Part.fSSAP;
- break;
-
- default: // for Ethernet address do nothing
- break;
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routines builds the message block for the Indication message. The appropriate
- // information is set in the message. The destination and source dlsaps are put
- // into the M_PROTO block. These dlsaps could be classic ethernet, 802.2, or IPX.
- // The "data" portion of the message only contains pure data. For 802.2 this
- // is everything past the snap or sap if there is no snap. For classic ethernet
- // this is everything past the protocol type. For IPX this includes FF FF 03 +
- // the data.
- //
- // Input:
- // mp - message block that contains the info for building a indication message
- // dlsap_length - the number of bytes in the mp message block
- //
- // Output:
- // returns a message block that contains an the Indication message
- //
- //-----------------------------------------------------------------------------------------
- void BuildUnitDataIndication(DLPIStream *theStream, mblk_t *mp,
- UInt16 destAddrLength, UInt16 headerHideLength)
- {
- mblk_t *nmp;
- dl_unitdata_ind_t *ind;
- SInt32 addressType;
- T8022FullPacketHeader *packetHeader;
- T8022AddressStruct *srcAddr,*destAddr;
-
- // Allocate the dl_unitdata_ind_t message, and fill it in.
- if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + (2 * destAddrLength), BPRI_HI)) == NULL)
- {
- freemsg(mp);
- return;
- }
-
- nmp->b_datap->db_type = M_PROTO;
-
- ind = (dl_unitdata_ind_t*)nmp->b_rptr;
- ind->dl_primitive = DL_UNITDATA_IND;
- ind->dl_dest_addr_length = destAddrLength;
- ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
- ind->dl_src_addr_length = destAddrLength;
- ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + destAddrLength;
-
- addressType = GetAddressType(mp->b_rptr);
- if (addressType == keaStandardAddress)
- ind->dl_group_address = 0;
- else
- ind->dl_group_address = addressType; // broadcast or multicast
-
- nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + destAddrLength + destAddrLength);
-
- packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
-
- destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
- srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
-
- BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
-
- if (theStream->streamFlags & kReadRawPackets) // a raw packet comming in
- ind->dl_group_address |= keaRawPacketBit; // marks packet as raw
- else
- mp->b_rptr += headerHideLength; // "hide" the ethernet and protocol header(s)
-
- linkb(nmp, mp); // append dlpi header to the packet data message block.
- putnext(theStream->readQueue, nmp); // pass the message up the stream
- return;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // Process M_DATA mblk_ts from the device (the lower half of the driver.
- // This is the basic client stream service routine to prepend the right kind
- // of DLPI information to the raw data coming in off the wire. The packet is
- // then placed on the stream read queue for processing by our client.
- //
- // Input:
- // theStream - the stream that will receive this packet
- // mp - the message block that contains the received packet
- //
- // Output:
- // no return value explicitly
- //
- //-----------------------------------------------------------------------------------------
- void HandleReceivedPacket(DLPIStream *theStream, mblk_t *mp, UInt16 packetType)
- {
- Boolean isTest = kFalse;
- Boolean isXID = kFalse;
- Boolean isCommand = kTrue;
- UInt16 destAddrLength;
- UInt32 headerHideLength;
- UInt8 ctrl;
- Boolean is8022 = kFalse;
-
- switch( packetType )
- {
- case kPktDIX:
- destAddrLength = kEnetPhysicalAddressLength;
- headerHideLength = kEnetPacketHeaderLength;
- break;
- case kPkt8022SAP:
- destAddrLength = kEnetAndSAPAddressLength;
- headerHideLength = kEnetPacketHeaderLength + k8022BasicHeaderLength;
- is8022 = kTrue;
- break;
- case kPkt8022SNAP:
- destAddrLength = kEnetAndSAPAddressLength + k8022SNAPLength;
- headerHideLength = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
- is8022 = kTrue;
- break;
- case kPktIPX:
- destAddrLength = kEnetPhysicalAddressLength;
- headerHideLength = kEnetPacketHeaderLength;
- break;
- default:
- break;
- }
-
- if (theStream->streamFlags & kReadRawPackets) // raw packet comming in
- {
- BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
- return;
- }
-
-
- if (is8022)
- {
- ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
- isTest = (ctrl & 0xEF) == 0xE3;
- isXID = (ctrl & 0xEF) == 0xAF;
- isCommand = (((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP & 1) == 0;
-
- if (isTest && isCommand && (theStream->streamFlags & kAutoTest))
- {
- DoTestResponse(theStream, mp);
- return;
- }
-
- if (isXID && isCommand && (theStream->streamFlags & kAutoXID))
- {
- DoXidResponse(theStream, mp);
- return;
- }
-
- if (isTest || isXID) // indication (request) or confirmation (response, auto off)
- {
- BuildXidTestConfirmIndication(theStream, mp, destAddrLength, headerHideLength);
- return;
- }
-
- }
-
- // send packet up the stream
- BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called because the callee wants to check if the passed in
- // multicast ethernet address has already been registered with this stream. A linked
- // list of message blocks that contain 1 registered multicast address is kept on
- // a per stream basis. This routine call also be used to dequeue the mb that
- // contains the already registered multicast address.
- //
- // Input:
- // multicastQueue - pointer to a queue header for the linked list of mb's
- // reqaddr - ethernet multicast address to be checked against the linked list
- // dequeueBlock - determines whether the mb containing the registered multicast
- // should be dequeued from the linked list
- //
- // Output:
- // returns null if no match is found, returns the mb if it is found
- //
- //-----------------------------------------------------------------------------------------
- mblk_t *IsAddressRegistered(QHdr *multicastQueue,UInt8 *reqaddr, Boolean dequeueBlock,
- UInt16 interruptMask)
- {
- mblk_t *mbWalker;
-
-
- ABCVendorDisableInterrupts(interruptMask);
-
- if ((mbWalker = (mblk_t *)multicastQueue->qHead) == NULL)
- {
- ABCVendorEnableInterrupts(interruptMask);
- return NULL;
- }
-
- while (mbWalker)
- {
- if (CheckAddressMatch((UInt8 *)mbWalker->b_rptr, reqaddr, kEnetPhysicalAddressLength))
- {
- if (dequeueBlock)
- DequeueElement(multicastQueue,(QElem *)mbWalker, 0);
- break;
- }
- else
- mbWalker = mbWalker->b_next; // check the next mb/address
- }
-
- ABCVendorEnableInterrupts(interruptMask);
-
-
- return mbWalker;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles removing a registered multicast address from the stream.
- // First the address is checked to make sure it is a valid multicast address.
- // Then the mc is checked to see if it has actually been registered. If
- // everything passes then an OK ack is sent to the client. If not then an error
- // ack is sent.
- //
- // Input:
- // theStream - the stream requesting the disable
- // mp - message block containing the DL_DISABMULTI_REQ parameters
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoDisableMulticast(DLPIStream *theStream, mblk_t *mp)
- {
- dl_disabmulti_req_t* req = (dl_disabmulti_req_t*)mp->b_rptr;
- UInt8 *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
- mblk_t *mc;
-
- if (GetAddressType(reqaddr) != keaMulticast)
- {
- DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
- return (kdlpiDONE);
- }
-
- // find address and dequeue if found
- if ((mc = IsAddressRegistered(&theStream->multicastQueue,reqaddr,kTrue,kRxInterrupts)) != NULL)
- {
- freemsg(mc);
- ABCVendorUnregisterMulticast(reqaddr); // turn off multicast addr if no one is using it
-
- if (theStream->multicastQueue.qHead == NULL)
- theStream->streamFlags &= ~kAcceptMulticasts; // no longer check multicast packets
-
- DoOKAck(theStream, mp, DL_DISABMULTI_REQ);
- return (kdlpiDONE);
- }
-
- DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
- return (kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles the DL_ENABMULTI_REQ call to enable a multicast address
- // for a certain stream. The address is checked to make sure it is indeed a
- // multicast address. Then a check is done to see if the address has already
- // been registered.
- //
- // If everything passes then an OK ack is sent to the client. If not then an error
- // ack is sent.
- //
- // Input:
- // theStream - the stream requesting the enable
- // mp - message block containing the DL_ENABMULTI_REQ parameters
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoEnableMulticast(DLPIStream *theStream, mblk_t *mp)
- {
-
- dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)mp->b_rptr;
- UInt8 *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
- mblk_t *mc;
- SInt32 i;
-
- if (GetAddressType(reqaddr) == keaMulticast)
- {
- if (IsAddressRegistered(&theStream->multicastQueue,reqaddr,kFalse,kRxInterrupts))
- {
- DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
- return (kdlpiDONE);
- }
-
- if ((mc = allocb(kEnetPhysicalAddressLength, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, kEnetPhysicalAddressLength);
- return(kdlpiRETRY);
- }
-
- ABCVendorRegisterMulticast(reqaddr);
-
- for (i = 0; i < kEnetPhysicalAddressLength; i++)
- *mc->b_wptr++ = *reqaddr++;
-
- // add new address to multicast list
- EnqueueElement(&theStream->multicastQueue,(QElem *)mc,kBothTxRxInterrupts);
-
- DoOKAck(theStream, mp, DL_ENABMULTI_REQ);
-
- theStream->streamFlags |= kAcceptMulticasts; // on receive now check multicast packets
- }
- else
- DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
-
- return (kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is used to enable the write queue.
- //
- // Input:
- // p - the stream that contains the write queue that needs to be enabled
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void EnableWriteQueue(long p)
- {
- DLPIStream *theStream = (DLPIStream *)p;
-
- if (theStream->readQueue)
- {
- theStream->idType = NULL; // mark us as no event waiting
- qenable(WR(theStream->readQueue));
- }
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds and sends (if possible) an error ack for a particular call
- // made by a client. If memory cannot be allocated for the ack message block
- // then a scheduled event is queued.
- //
- // Input:
- // theStream - the stream to send the error ack to
- // ack_mp - the message block to use for the ack
- // prim - the primitive or call that caused the error ack
- // err - error number to be placed in the error ack message block
- // uerr - the unix error number
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoErrorAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 prim, UInt32 err, UInt32 uerr)
- {
- dl_error_ack_t *errp;
-
- if (ack_mp == NULL)
- {
- if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
- return(kdlpiRETRY);
- }
- }
- else // so we have a message block
- {
- if (ack_mp->b_datap->db_ref != 1) // is anybody else using this message data
- {
- freemsg(ack_mp);
- if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
- return(kdlpiRETRY);
- }
- }
- else // we are the only ones using this message
- {
- ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
- if (ack_mp->b_cont != NULL)
- {
- freemsg(ack_mp->b_cont);
- ack_mp->b_cont = NULL;
- }
- }
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- errp = (dl_error_ack_t *)ack_mp->b_wptr;
- errp->dl_primitive = DL_ERROR_ACK;
- errp->dl_error_primitive = prim;
- errp->dl_errno = err;
- errp->dl_unix_errno = uerr;
- ack_mp->b_wptr += sizeof(dl_error_ack_t);
- putnext(theStream->readQueue, ack_mp);
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks if the stream has already been registered by a certain sap.
- // The sap could also contain a snap.
- //
- // Input:
- // theStream - the stream used for checking the new sap
- // sap - the sap plus possibly snap that is being checked to see if it is already
- // registered
- // len - the number of bytes valid in the sap
- //
- // Output:
- // returns kTrue if sap is already registered, returns kFalse if not registered
- //
- //-----------------------------------------------------------------------------------------
- SInt32 FindSnap(DLPIStream *theStream, UInt8 *sap, SInt32 len)
- {
- DLPIStream *tempStream = (DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
-
- while (tempStream)
- {
- if (tempStream->streamFlags & kSnapStream)
- {
- if (CheckAddressMatch(sap, tempStream->snap, len))
- return kTrue;
- }
- tempStream = tempStream->nextStream;
- }
- return kFalse;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine classifies a packet into the different types of protocols. For IPX
- // we need both the source and destination SAPs to make a protocol determination.
- //
- // Input:
- // thePacket - a message block the contains the received packet
- //
- // Output:
- // returns type of packet
- //
- //-----------------------------------------------------------------------------------------
- UInt16 ClassifyPacketType(UInt16 primarySAP, UInt16 secondarySAP)
- {
-
- if (primarySAP >= kMinDIXSAP)
- return kPktDIX;
-
- if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP))
- return kPktIPX;
-
- if (primarySAP == kSNAPSAP)
- return kPkt8022SNAP;
-
- if (primarySAP <= k8022GlobalSAP)
- return kPkt8022SAP;
-
- return kPktUnknown;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine extracts the sap information from the ethernet packet header.
- //
- // Input:
- // fullpkt - ptr to Ethernet packet header
- // sourceSAP - return source sap here
- // destSAP - return dest sap here
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ExtractSAPValues(T8022FullPacketHeader *fullpkt, UInt16 *sourceSAP, UInt16 *destSAP)
- {
-
-
- *destSAP = fullpkt->fEnetPart.fProto;
-
- if (*destSAP >= kMinDIXSAP) // classic ethernet
- *sourceSAP = *destSAP;
- else
- {
- *destSAP = fullpkt->f8022Part.fDSAP;
- *sourceSAP = fullpkt->f8022Part.fSSAP;
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks each stream to see if it "wants" the packet. In the loop
- // each stream that wants the packet is placed in a linked list (queue). After
- // all the streams are examined then the packet is passed to each stream (while loop).
- // If more than 1 stream wants the packet then n-1 streams receive a dupmsg packet
- // and the last stream receives the original.
- //
- // In order to build the list we have to jump through some hoops so we don't have
- // to allocate any memory. In the DLPIStream struct a rxPacketLink follows
- // the real link. We use the rxPacketLink field to link the streams together.
- // I should mention that the real link field keeps track of all the opened streams
- // for this piece of hw. So we build a list of streams that want the packet
- // and then we walk the list and send the packet to each stream. Since the
- // rxPacketLink is not at the beginning of the DLPIStream structure we must
- // subtract 4 from the value in the link to get back to the beginning of the
- // DLPIStream structure.
- //
- // Now why do we jump through so many whoops? Well we could just find a stream
- // that wants the packet and then dupmsg to each stream. After we exit the loop
- // then just free the original message. By doing all this fancy stuff we save
- // doing the dupmsg for one stream, in fact if only 1 stream wants the packet
- // then no duping is done. So we save some memory and time by not duping if we
- // don't have to. Make sense? Feel free to change it to the simpler method if
- // you want.
- //
- // Input:
- // theStream - the first stream in a list of streams that will be checked
- // mp - a message block that contains the received packet
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void FindStreamForReceivedPacket(DLPIStream *theStream, mblk_t *mp)
- {
- EnetPacketHeader *pkt = (EnetPacketHeader *)mp->b_rptr;
- T8022FullPacketHeader *fullpkt;
- Boolean isOurs;
- UInt16 packetType,sourceSAP,destSAP;
- mblk_t *copy_of_mp = NULL;
- SInt32 destAddressType;
- QHdr wantsPacketQueue;
- DLPIStream *fakeStream;
-
- // init queue for storing streams that want the rx packet
- wantsPacketQueue.qHead = NULL;
- wantsPacketQueue.qTail = NULL;
-
- fullpkt = (T8022FullPacketHeader *)pkt;
-
- ExtractSAPValues(fullpkt,&sourceSAP, &destSAP);
-
- packetType = ClassifyPacketType(sourceSAP,destSAP);
-
- destAddressType = GetAddressType(pkt->fDestAddr);
-
- for (; theStream; theStream = theStream->nextStream)
- {
- isOurs = kFalse;
- if (theStream->dlpiState == DL_UNBOUND) // can't send to unbound streams
- continue;
-
- // does this stream want all 802.2 packets?
- if ((theStream->streamFlags & kAcceptAll8022Packets) && (destSAP <= 0xff))
- {
- EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
- continue;
- }
-
- if (destSAP == theStream->dlsap)
- {
- if (theStream->streamFlags & kSnapStream) // check SNAPs if necessary
- isOurs = CheckAddressMatch(fullpkt->f8022Part.fSNAP, theStream->snap,
- k8022SNAPLength);
- else // no SNAP, found a match since saps match
- isOurs = kTrue;
-
- }
- else // Check for an 802.3 Group/Global (odd)
- {
- if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP))
- && (destSAP & 1) && TestGroupSAP(theStream, destSAP))
- isOurs = kTrue;
- }
-
- if (!isOurs) // this stream does not want this packet
- continue;
-
- // if this is a multicast packet, see if it is destined for an address we
- // are interested in
- if (isOurs && (destAddressType == keaMulticast) &&
- (theStream->streamFlags & kAcceptMulticasts))
- {
- isOurs = kFalse; // assume no match
- if (IsAddressRegistered(&theStream->multicastQueue,pkt->fDestAddr,kFalse, kNoInterrupts))
- isOurs = kTrue;
- }
-
- // add stream to our list if it can accept the packet
- if (isOurs && canput(theStream->readQueue->q_next))
- EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
- }
-
-
- // once all the streams that want this packet have been put on the queue we need
- // to go through the streams list, when multiple streams want the packet all
- // the streams get a duplicate except for the last stream which gets the original
- // this saves an extra duplicate
-
- /*zzz*/
- if (wantsPacketQueue.qHead == NULL)
- DebugStrErr ((ConstStr255Param) "\pNo one wanted message");
- else
- DebugStr1 ((ConstStr255Param) "\pSomeone wants this message");
- /*zzz*/
- if (wantsPacketQueue.qHead == NULL)
- freemsg(mp); // nobody wanted the message (packet)
- else
- { // 1 or more streams want this packet
- fakeStream = (DLPIStream *)wantsPacketQueue.qHead;
- theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
- while (theStream->rxPacketLink)
- {
- if ((copy_of_mp = dupmsg(mp)) != NULL)
- HandleReceivedPacket(theStream, copy_of_mp,packetType);
- fakeStream = theStream->rxPacketLink;
- theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
- }
- HandleReceivedPacket(theStream, mp,packetType); // send original
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles the info primitive/call from the client. The information is
- // collected from the DLPI and then placed in a message block that will be returned
- // to the client.
- //
- // Input:
- // theStream - the stream from which the information is collected
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoGeneralInfo(DLPIStream *theStream)
- {
- dl_info_ack_t *ackp;
- mblk_t *ack_mp;
- UInt32 saplen = 0;
- UInt32 addrlen = kEnetPhysicalAddressLength;
- UInt32 bcastlen = kEnetPhysicalAddressLength;
- UInt32 hdrlen = kEnetPacketHeaderLength;
- T8022AddressStruct *boundAddr;
-
- if (theStream->dlpiState != DL_UNBOUND)
- {
- saplen = (theStream->streamFlags & kSnapStream)
- ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength;
-
- if (theStream->dlsap == kSNAPSAP)
- hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength; // SNAP address
- else if ((theStream->dlsap <= kMax8022SAP) || (theStream->dlsap == kIPXSAP))
- hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength; // SAP or IPX
- else
- hdrlen = kEnetPacketHeaderLength; // basic Ethernet
- }
-
- if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen);
- return(kdlpiRETRY);
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_info_ack_t *)ack_mp->b_rptr;
-
- if ( theStream->streamFlags & kReadRawPackets )
- ackp->dl_max_sdu = kEnetTSDU; // for raw packet mode
- else
- ackp->dl_max_sdu = kEnetTSDU - hdrlen;
-
- ackp->dl_min_sdu = 1;
- ackp->dl_addr_length = addrlen + saplen;
- ackp->dl_mac_type = (gDLPIPrivateData->privateFlags & kpfFraming8022) ? DL_CSMACD : DL_ETHER;
- ackp->dl_reserved = 0;
- ackp->dl_sap_length = -saplen; // negative to indicate sap follows physical address
- ackp->dl_service_mode = DL_CLDLS;
- ackp->dl_qos_length = 0;
- ackp->dl_qos_offset = DL_UNKNOWN;
- ackp->dl_qos_range_length = 0;
- ackp->dl_qos_range_offset = DL_UNKNOWN;
- ackp->dl_provider_style = DL_STYLE1;
- ackp->dl_addr_offset = sizeof(dl_info_ack_t);
- ackp->dl_version = DL_VERSION_2;
- ackp->dl_brdcst_addr_length = bcastlen;
- ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen;
- ackp->dl_growth = 0;
- ackp->dl_primitive = DL_INFO_ACK;
- ackp->dl_current_state = theStream->dlpiState;
- ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen;
-
- boundAddr = ((T8022AddressStruct*)(ack_mp->b_rptr + ackp->dl_addr_offset));
-
- OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,boundAddr->fHWAddr);
- if (saplen)
- {
- boundAddr->fSAP = theStream->dlsap;
- if (theStream->streamFlags & kSnapStream)
- OTCopy8022SNAP(theStream->snap, boundAddr->fSNAP);
- }
-
- OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset);
-
- putnext(theStream->readQueue, ack_mp);
- return (kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This is a utility routine that compares to address (byte arrays).
- //
- // Input:
- // a - address array 1
- // b - address array 2
- // len - number of bytes that should match in the arrays
- //
- // Output:
- // returns kTrue if they match and kFalse if they do not
- //
- //-----------------------------------------------------------------------------------------
- Boolean CheckAddressMatch(UInt8 *a, UInt8 *b, SInt32 len)
- {
- register SInt32 i;
-
- for (i = 0; i < len; i++)
- {
- if (*a++ != *b++)
- return kFalse;
- }
-
- return kTrue;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine fills in the ok ack message block and then passes it to the client.
- //
- // Input:
- // theStream - the stream that will be passed the ok ack
- // ack_mp - ok ack message block
- // primitive - call that is being ack'd
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoOKAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 primitive)
- {
- dl_ok_ack_t *ackp;
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
- ackp = (dl_ok_ack_t *)ack_mp->b_wptr;
- ackp->dl_primitive = DL_OK_ACK;
- ackp->dl_correct_primitive = primitive;
- ack_mp->b_wptr += sizeof(dl_ok_ack_t);
- putnext(theStream->readQueue, ack_mp);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine acks the get physical address (ethernet) call from the client.
- // An ack message block is built and filled in. If this message block cannot
- // be allocated then a scheduler task is queued.
- //
- // Input:
- // theStream - the stream requesting the physical address information
- // mp - the message block requesting the physical address
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoPhysicalAddressAck(DLPIStream *theStream, mblk_t *mp)
- {
- mblk_t *ack_mp;
- dl_phys_addr_ack_t *ackp;
- dl_phys_addr_req_t *addrReq = (dl_phys_addr_req_t *)mp->b_rptr;
- UInt8 addressArray[kEnetPhysicalAddressLength];
-
- if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, DL_PHYS_ADDR_ACK_SIZE + kEnetPhysicalAddressLength);
- return(kdlpiRETRY);
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_phys_addr_ack_t *)ack_mp->b_wptr;
- ackp->dl_primitive = DL_PHYS_ADDR_ACK;
- ackp->dl_addr_length = kEnetPhysicalAddressLength;
- ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
- ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength;
- switch(addrReq->dl_addr_type)
- {
- case DL_CURR_PHYS_ADDR:
- OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,
- ack_mp->b_rptr + ackp->dl_addr_offset);
- break;
- case DL_FACT_PHYS_ADDR:
- ABCVendorGetFactoryEthernetAddress(addressArray);
- OTCopy48BitAddress(addressArray, ack_mp->b_rptr + ackp->dl_addr_offset);
- break;
- default:
- break;
- }
-
- putnext(theStream->readQueue, ack_mp);
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is NOT finished yet. The statistics will be returned through this
- // call, but the format of the structure(s) has not been determined. The code
- // that calls this routine (WriteServiceRoutine) has been commented out so this
- // routine will never get called. I added this routine so that it is a placeholder
- // for when the decision has been made on how to return the statistics.
- //
- // Input:
- // theStream - the stream requesting the physical address information
- // mp - the message block requesting the statistics
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoStatisticsAck(DLPIStream *theStream, mblk_t *mp)
- {
- mblk_t *ack_mp;
- dl_get_statistics_ack_t *statAckStruct;
- UInt16 statSize;
-
- statSize = 100; // this is not a valid number, just a number that lets us compile
-
- if ((ack_mp = allocb(sizeof(dl_get_statistics_ack_t) + statSize, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_get_statistics_ack_t) + statSize);
- return(kdlpiRETRY);
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- statAckStruct = (dl_get_statistics_ack_t *)ack_mp->b_wptr;
- statAckStruct->dl_primitive = DL_GET_STATISTICS_ACK;
-
- statAckStruct->dl_stat_length = statSize;
- statAckStruct->dl_stat_offset = sizeof(dl_get_statistics_ack_t);
- ack_mp->b_wptr += sizeof(dl_get_statistics_ack_t) + statSize;
-
-
- // WE NEED TO COPY OUR STATISTICS TO THE MESSAGE BLOCK
-
-
- putnext(theStream->readQueue, ack_mp);
- return(kdlpiDONE);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine accepts subsbind primitives. A subsbind is used to register
- // 802.2 SAP group addresses and snaps. snaps can only be bound to a stream
- // that has a dlsap of 0xAA.
- //
- // DL_PEER_BIND - for group addresses
- // DL_HIERARCHICAL_BIND - for additional snaps
- //
- // Input:
- // theStream - the stream being bound
- // mp - the message block containing the subsbind parameters
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 SubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
- {
- dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)mp->b_rptr;
- mblk_t *ack_mp;
- UInt8 *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
- SInt32 length = req->dl_subs_sap_length;
- UInt16 theSap;
- SInt32 error = kOTNoError;
-
- if (theStream->dlpiState != DL_IDLE)
- return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0));
-
- theSap = *((UInt16 *)sap);
-
- switch(req->dl_subs_bind_class)
- {
- case DL_PEER_BIND:
- if (theStream->dlsap <= kMax8022SAP)
- {
- if ((theSap & 1) && (length == sizeof(theSap)))
- SetGroupSAP(theStream, theSap);
- else
- if (theSap == 0x0000) // special case to receive all 802.2 packets
- theStream->streamFlags |= kAcceptAll8022Packets;
- else
- error = DL_BADADDR;
- }
- else
- error = DL_UNSUPPORTED;
- break;
-
- case DL_HIERARCHICAL_BIND:
- if (theStream->dlsap == kSNAPSAP)
- {
- if (theStream->streamFlags & kSnapStream)
- error = DL_TOOMANY; // only one SNAP binding allowed
- else
- {
- OTCopy8022SNAP(sap, theStream->snap);
- theStream->streamFlags |= kSnapStream;
- }
- }
- else
- error = DL_BADADDR;
- break;
-
- default:
- error = DL_UNSUPPORTED;
- break;
- }
-
-
- if (error)
- return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, error, 0));
-
- if ((ack_mp = BuildSubsBindAck(theStream, sap, length)) == NULL)
- return (kdlpiRETRY);
-
- freemsg(mp);
- theStream->dlpiState = DL_IDLE;
- putnext(theStream->readQueue, ack_mp);
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds the ack for the subsbind call. If the ack message block
- // cannot be scheduled then a task is queued.
- //
- // Input:
- // theStream - the stream that will be sent the subsbind ack
- // sap - the sap to be returned in the ack mb
- // length - number of valid bytes in the sap
- //
- // Output:
- // returns ack message block
- //
- //-----------------------------------------------------------------------------------------
- mblk_t *BuildSubsBindAck(DLPIStream *theStream, UInt8 *sap, SInt32 length)
- {
- dl_subs_bind_ack_t *ackp;
- mblk_t *mp;
-
- if ((mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, sizeof(dl_subs_bind_ack_t) + length);
- return(NULL);
- }
-
- mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_subs_bind_ack_t *)mp->b_wptr;
- bzero(ackp, sizeof(dl_subs_bind_ack_t) + length);
- ackp->dl_primitive = DL_SUBS_BIND_ACK;
- ackp->dl_subs_sap_length = length;
- ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0;
- mp->b_wptr += sizeof(dl_subs_bind_ack_t);
- if (length)
- bcopy(sap, mp->b_wptr, length);
- mp->b_wptr += length;
-
- return(mp);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles changing the Ethernet address of the card. All streams
- // opened on this port must be in the unbound state. The address length must
- // be equal to the Ethernet physical length.
- //
- // Input:
- // theStream - the stream requesting the new physical address
- // mp - the message block containing the physical address
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoSetPhysicalAddress(DLPIStream *theStream, mblk_t *mp)
- {
- dl_set_phys_addr_req_t *req = (dl_set_phys_addr_req_t *)mp->b_rptr;
- SInt32 length = req->dl_addr_length;
- mblk_t *ack_mp;
- UInt8 *physicalAddress = ((UInt8 *)req) + req->dl_addr_offset;
-
-
- if (!AreAllStreamsUnbound()) // all streams must be unbound, if error abort
- {
- if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
- return(kdlpiRETRY);
- freemsg(mp);
- return(kdlpiDONE);
- }
-
- if (length != kEnetPhysicalAddressLength) // must only contain Ethernet address
- {
- if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0) == kdlpiRETRY)
- return(kdlpiRETRY);
- freemsg(mp);
- return(kdlpiDONE);
- }
-
- if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
- return(kdlpiRETRY);
- }
-
- ABCVendorSetEthernetAddress(physicalAddress);
-
- freemsg(mp);
-
- DoOKAck(theStream, ack_mp, DL_SET_PHYS_ADDR_REQ);
-
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles the unsubsbind primitive/call. A snap can be unbound and
- // also a 802.2 group address. An ok ack message block is sent to the client
- // if everything goes well and error ack if not.
- //
- // Input:
- // theStream - the stream requesting the unsubsbind
- // mp - the message block containing the unsubsbind parameters
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 UnSubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
- {
- dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)mp->b_rptr;
- UInt8 *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
- SInt32 length = req->dl_subs_sap_length;
- mblk_t *ack_mp;
- SInt32 error = 0;
-
- if (theStream->dlpiState != DL_IDLE)
- {
- if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
- return(kdlpiRETRY);
- freemsg(mp);
- return(kdlpiDONE);
- }
-
- if (length == k8022SAPLength)
- {
- if ((*sap & 1) && (*sap != kIPXSAP))
- {
- if (theStream->dlsap <= kMax8022SAP)
- ClearGroupSAP(theStream, *sap);
- else
- error = DL_UNSUPPORTED;
- }
- else
- error = DL_BADADDR;
- }
- else
- if (length == k8022SNAPLength)
- {
- if (theStream->dlsap == kSNAPSAP)
- {
- if (theStream->streamFlags & kSnapStream)
- {
- if (CheckAddressMatch(theStream->snap, sap, length) == kFalse)
- error = DL_BADADDR;
- }
- else
- error = DL_BADADDR;
- }
- else
- error = DL_UNSUPPORTED;
- }
-
- if (error)
- {
- if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, error, 0) == kdlpiRETRY)
- return(kdlpiRETRY);
- freemsg(mp);
- return(kdlpiDONE);
- }
-
- if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
- return(kdlpiRETRY);
- }
-
- freemsg(mp);
- theStream->streamFlags &= ~kSnapStream;
- DoOKAck(theStream, ack_mp, DL_SUBS_UNBIND_REQ);
-
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine if called when the client wishes to unbind the stream. An ok ack is
- // sent to the client if everything goes well.
- //
- // Input:
- // theStream - the stream being unbound
- // mp - the message block containing the unbind message
- //
- // Output:
- // returns status of the call
- //
- //-----------------------------------------------------------------------------------------
- SInt32 UnBindTheStream(DLPIStream *theStream, mblk_t *mp)
- {
- mblk_t *ack_mp;
-
- if (theStream->dlpiState != DL_IDLE)
- {
- if (DoErrorAck(theStream, 0, DL_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
- return(kdlpiRETRY);
- freemsg(mp);
- return(kdlpiDONE);
- }
-
- if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL)
- {
- DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
- return(kdlpiRETRY);
- }
-
- freemsg(mp);
-
- //if (putctl1(theStream->readQueue->q_next, M_FLUSH, FLUSHRW) == 0)
-
- theStream->dlpiState = DL_UNBOUND;
- theStream->dlsap = 0;
- DoOKAck(theStream, ack_mp, DL_UNBIND_REQ);
- return(kdlpiDONE);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This utility routine sets a bit in the group sap array that indicates if a
- // certain group sap has been bound (subsbind).
- //
- // Input:
- // theStream - the stream for the group sap
- // sap - group sap that needs registration bit set
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void SetGroupSAP(DLPIStream *theStream, UInt8 sap)
- {
- theStream->group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask));
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This utility routine is used to clear a registration bit for a certain sap.
- //
- // Input:
- // theStream - the stream for the group sap
- // sap - group sap that needs registration bit cleared
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void ClearGroupSAP(DLPIStream *theStream, UInt8 sap)
- {
- theStream->group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask));
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This utility routine tests a registration bit against a sap.
- //
- // Input:
- // theStream - the stream for the group sap
- // sap - group sap that needs checking
- //
- // Output:
- // returns kTrue is sap is registered, kFalse if not
- //
- //-----------------------------------------------------------------------------------------
- Boolean TestGroupSAP(DLPIStream *theStream, UInt8 sap)
- {
- return 0 != (theStream->group_sap[sap >> kGSshift] & (1L << ((sap >> 1) & kGSmask)));
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds the uderror message block and sends it to the stream's client.
- //
- // Input:
- // theStream - the stream sending the message block
- // dest - the destination address
- // destlen - number of bytes valid in dest parameter
- // err - error to retrun in the message block
- // uerr - unix error returned in the message block
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoUdError(DLPIStream *theStream, UInt8 *dest, UInt32 destlen, UInt32 err,
- UInt32 uerr)
- {
- dl_uderror_ind_t *errp;
- mblk_t *bp;
- SInt32 i;
-
- i = sizeof(dl_uderror_ind_t) + destlen;
- if ((bp = allocb(i, BPRI_HI)) == NULL)
- return;
- bp->b_datap->db_type = M_PROTO;
- errp = (dl_uderror_ind_t *)bp->b_wptr;
- errp->dl_primitive = DL_UDERROR_IND;
- errp->dl_errno = err;
- errp->dl_unix_errno = uerr;
- errp->dl_dest_addr_length = destlen;
- errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
- bp->b_wptr += sizeof(dl_uderror_ind_t);
- bcopy((UInt8 *)dest, (UInt8 *)bp->b_wptr, destlen);
- bp->b_wptr += destlen;
- putnext(theStream->readQueue, bp);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called when someone cannot allocate a message block for an ok ack
- // or error ack. This routine says call me when you have enough memory for my
- // message block.
- //
- // Input:
- // theStream - the stream to disable until memory is available
- // size - number of bytes needed for the message block
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoWriteScheduler(DLPIStream *theStream, SInt32 size)
- {
-
- theStream->timeoutID = bufcall(size, BPRI_HI, EnableWriteQueue, (SInt32)theStream);
- if (theStream->timeoutID)
- theStream->idType = kdlpiBufcallType;
- else
- if ((*((UInt32 *)theStream->bufferTimerMsg->b_rptr)) == NULL) // is timer unused?
- {
- *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = kEnableQueueTimerMsg;
- mi_timer(theStream->bufferTimerMsg,500); // send us a timer message in 1/2 sec
- }
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks if all the streams are in the unbound state.
- //
- // Input:
- // NONE
- //
- // Output:
- // kTrue, if all the streams are unbound
- // kFalse, if some stream is not in the unbound state
- //
- //-----------------------------------------------------------------------------------------
-
- Boolean AreAllStreamsUnbound(void)
- {
- mblk_t *mbWalker;
- Boolean unbound = kTrue;
-
- mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
-
- while (mbWalker && unbound)
- {
- if (((DLPIStream *)mbWalker)->dlpiState == DL_UNBOUND)
- mbWalker = mbWalker->b_next;
- else
- unbound = kFalse;
- }
-
- return unbound;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine processes a message block that contains a packet that needs to
- // be transmitted over the wire. Error ack message blocks are sent to the
- // client if errors appear during processing.
- //
- // Input:
- // theStream - the stream requesting the packet transmission
- // mp - the message block containing the packet
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoUnitData(DLPIStream *theStream, mblk_t *mp)
- {
-
- dl_unitdata_req_t* req;
-
- req = (dl_unitdata_req_t *)mp->b_rptr;
-
- if (theStream->dlpiState != DL_IDLE)
- {
- DoUdError(theStream, ((UInt8 *)req) + req->dl_dest_addr_offset,
- req->dl_dest_addr_length, DL_OUTSTATE, 0);
- freemsg(mp);
- return;
- }
-
- if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
- PreparePacketToBeSent(mp);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine sends Test requests and responses. The test primitives are only
- // valid on 802.2 streams. A request packet should not be sent if the client
- // requested auto handling of the test messages.
- //
- // Input:
- // theStream - the stream that wants to send the test
- // mp - message block that contains the data to send
- // requestFlag - kTrue if mp is a test request, kFalse if mp is a test response
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- SInt32 SendTestPacket(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
- {
- Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
-
- if (!is8022)
- {
- freemsg(mp);
- return kdlpiDONE;
- }
-
- if (requestFlag && (theStream->streamFlags & kAutoTest))
- return( DoErrorAck(theStream, mp, DL_TEST_REQ, DL_TESTAUTO, 0));
-
- if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
- PreparePacketToBeSent(mp);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine sends XID requests and responses. The XID primitives are only
- // valid on 802.2 streams. A request packet should not be sent if the client
- // requested auto handling of the XID messages.
- //
- // Input:
- // theStream - the stream that wants to send the XID
- // mp - message block that contains the data to send
- // requestFlag - kTrue if mp is a XID request, kFalse if mp is a XID response
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- SInt32 DoXID(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
- {
- Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
-
- if (!is8022)
- {
- freemsg(mp);
- return kdlpiDONE;
- }
-
- if (requestFlag && (theStream->streamFlags & kAutoTest))
- return( DoErrorAck(theStream, mp, DL_XID_REQ, DL_XIDAUTO, 0));
-
- if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
- PreparePacketToBeSent(mp);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine builds the header block for Test/XID Indication/confirm packets.
- // So this routine can receive 4 types of packets for which it must build
- // a correct header so that the entire message can be passed up to our client.
- //
- // The headers for each of the different types of packets is exactly the
- // same so we will just us the test indication structure for all the packet
- // types.
- //
- // Input:
- // mp - message block that contains the info for building a test message
- // dlsap_length - the number of bytes in the mp message block
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void BuildXidTestConfirmIndication(DLPIStream *theStream, mblk_t *mp,
- UInt16 destAddrLength, UInt16 headerHideLength)
- {
- UInt32 primitive;
- mblk_t *nmp;
- dl_test_ind_t* ind;
- UInt8 ssap = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP;
- UInt8 ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
- T8022FullPacketHeader *packetHeader;
- T8022AddressStruct *srcAddr,*destAddr;
-
- if ((ctrl & 0xEF) == 0xE3)
- primitive = (ssap & 1) ? DL_TEST_CON : DL_TEST_IND;
- else if ((ctrl & 0xEF) == 0xAF)
- primitive = (ssap & 1) ? DL_XID_CON : DL_XID_IND;
- else
- return;
-
- // Allocate a dl_test_(ind,con,xid)_t message, and fill it in.
- if ((nmp = allocb(sizeof(dl_test_ind_t) + (destAddrLength * 2), BPRI_HI)) == NULL)
- {
- freemsg(mp);
- return;
- }
-
- nmp->b_datap->db_type = M_PROTO;
- ind = (dl_test_ind_t*)nmp->b_rptr;
- ind->dl_primitive = primitive;
- ind->dl_flag = (ctrl & 0x10) ? DL_POLL_FINAL : 0;
- ind->dl_dest_addr_length = destAddrLength;
- ind->dl_dest_addr_offset = sizeof(dl_test_ind_t);
- ind->dl_src_addr_length = destAddrLength;
- ind->dl_src_addr_offset = sizeof(dl_test_ind_t) + destAddrLength;
- nmp->b_wptr += (sizeof(dl_test_ind_t) + destAddrLength + destAddrLength);
-
- packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
-
- destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
- srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
-
- BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
-
- mp->b_rptr += headerHideLength; // "hide" the ethernet and protocol header(s)
-
- // Append data to M_PROTO IND/TEST/XID block & pass it on to the client stream.
- linkb(nmp, mp);
- putnext(theStream->readQueue, nmp); // pass the message up the stream
- return;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine sends a test response packet that was created from the test request
- // that was received. When auto handling is turned on during the bind, the dlpi
- // sends test responses when it receives a test request.
- //
- // To send the response a control message block is built from the information in
- // the received packet. The Ethernet and protocol is then hidden in the original
- // request message block. The two blocks are then linked together and passed to
- // the send unit data routine.
- //
- // Input:
- // theStream - the stream sending the test reponse
- // mp - the message block containing the test request
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoTestResponse(DLPIStream *theStream, mblk_t *mp)
- {
- T8022FullPacketHeader *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
- Boolean isSnap;
- UInt32 destAddrLength;
- UInt32 headerHideCount;
- mblk_t *nmp;
- dl_test_res_t *responseStruct;
- T8022AddressStruct *destAddrTemplate;
-
- /*zzz*/
- sprintf (debugStr, "DoTestResponse, theStream = %lx, mp = %lx", (long) theStream, (long) mp);
- DebugStr1 ((ConstStr255Param) c2pstr (debugStr));
- /*zzz*/
- // since test is only valid for 802.2 we start we the basic values
- destAddrLength = kEnetAndSAPAddressLength;
- headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
- isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
-
- if (isSnap)
- {
- destAddrLength += k8022SNAPLength;
- headerHideCount += k8022SNAPLength;
- }
-
- // Allocate the dl_test_res_t message, and fill it in
- if ((nmp = allocb(sizeof(dl_test_res_t) + destAddrLength, BPRI_HI)) == NULL)
- {
- freemsg(mp);
- return;
- }
-
- nmp->b_datap->db_type = M_PROTO;
-
- responseStruct = (dl_test_res_t *)nmp->b_rptr;
- responseStruct->dl_primitive = DL_TEST_RES;
- responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
- responseStruct->dl_dest_addr_length = destAddrLength;
- responseStruct->dl_dest_addr_offset = sizeof(dl_test_res_t);
-
- nmp->b_wptr += sizeof(dl_test_res_t);
- destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
-
- OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
- destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
-
- if (isSnap)
- OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
-
- nmp->b_wptr += destAddrLength;
- mp->b_rptr += headerHideCount;
-
- linkb(nmp, mp);
-
- /*zzz*/
- sprintf (debugStr, "DoTestResponse calling DoUnitData, theStream = %lx, nmp = %lx", (long) theStream, (long) nmp);
- DebugStr1 ((ConstStr255Param) c2pstr (debugStr));
- /*zzz*/
- DoUnitData(theStream, nmp);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine sends a xid response packet that was created from the xid request
- // that was received. When auto handling is turned on during the bind, the dlpi
- // sends xid responses when it receives a xid request.
- //
- // To send the response a control message block is built from the information in
- // the received packet. The Ethernet and protocol header is then hidden in the original
- // request message block. The two blocks are then linked together and passed to
- // the send unit data routine.
- //
- // Input:
- // theStream - the stream generating the xid response
- // mp - the message block containing the xid request message
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void DoXidResponse(DLPIStream *theStream, mblk_t *mp)
- {
- T8022FullPacketHeader *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
- Boolean isSnap;
- UInt32 destAddrLength;
- UInt32 headerHideCount;
- mblk_t *nmp;
- dl_xid_res_t *responseStruct;
- T8022AddressStruct *destAddrTemplate;
-
- // since xid is only valid for 802.2 we start we the basic values
- destAddrLength = kEnetAndSAPAddressLength;
- headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
- isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
-
- if (isSnap)
- {
- destAddrLength += k8022SNAPLength;
- headerHideCount += k8022SNAPLength;
- }
-
- // Allocate the dl_xid_res_t message, and fill it in
- if ((nmp = allocb(sizeof(dl_xid_res_t) + destAddrLength, BPRI_HI)) == NULL)
- {
- freemsg(mp);
- return;
- }
-
- nmp->b_datap->db_type = M_PROTO;
-
- responseStruct = (dl_xid_res_t *)nmp->b_rptr;
- responseStruct->dl_primitive = DL_XID_RES;
- responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
- responseStruct->dl_dest_addr_length = destAddrLength;
- responseStruct->dl_dest_addr_offset = sizeof(dl_xid_res_t);
-
- nmp->b_wptr += sizeof(dl_xid_res_t);
- destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
-
- OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
- destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
-
- if (isSnap)
- OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
-
- nmp->b_wptr += destAddrLength;
- mp->b_rptr += headerHideCount; // hide the ethernet and protocol headers
-
- AddXIDInfoToPacketData(theStream,nmp, mp); // send packet after adding xid info
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine trys to add some xid information to the start of the packet
- // data. Before we can modify the data we must make sure that the message
- // is not being used by anyone else. If that is kTrue then we "backup" the
- // read pointer by 3 bytes and place the xid info at the beginning.
- //
- // If the message is being used by someone else then an attempt to copy it is made.
- // If that goes okay then the original message is no longer needed so we free it.
- //
- // Input:
- // theStream - the stream generating the xid response
- // mp - the message block containing the xid request message
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void AddXIDInfoToPacketData(DLPIStream *theStream, mblk_t *headerMB, mblk_t *dataMB)
- {
- mblk_t *theMB;
-
- if (dataMB->b_datap->db_ref != 1) // is anybody else using this message data
- {
- if ((theMB = copymsg(dataMB)) == NULL) // try to make a copy of the message
- {
- freemsg(headerMB); // could not make copy so lets just drop the packet
- freemsg(dataMB);
- return;
- }
- else
- {
- freemsg(dataMB); // free the original
- dataMB = theMB;
- }
- }
-
-
- dataMB->b_rptr -= 3; // need to prepend xid response information before data
-
- // this xid response information can be found in the 802.2 spec., p. 52
- dataMB->b_rptr[0] = 0x81; // XID Format Identifier, IEEE Basic Format
- dataMB->b_rptr[1] = 0x01; // Type 1 LLC
- dataMB->b_rptr[2] = 0x00; // Receive window size, we now default to 0
-
- linkb(headerMB, dataMB);
- DoUnitData(theStream, headerMB);
-
- }
-
-
-
-